﻿#region File and License Information
/*
<File>
	<License Type="BSD">
		Copyright © 2009 - 2015, Outcoder. All rights reserved.
	
		This file is part of Calcium (http://calciumsdk.net).

		Redistribution and use in source and binary forms, with or without
		modification, are permitted provided that the following conditions are met:
			* Redistributions of source code must retain the above copyright
			  notice, this list of conditions and the following disclaimer.
			* Redistributions in binary form must reproduce the above copyright
			  notice, this list of conditions and the following disclaimer in the
			  documentation and/or other materials provided with the distribution.
			* Neither the name of the <organization> nor the
			  names of its contributors may be used to endorse or promote products
			  derived from this software without specific prior written permission.

		THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
		ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
		WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
		DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
		DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
		(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
		LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
		ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
		(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
		SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
	</License>
	<Owner Name="Daniel Vaughan" Email="danielvaughan@outcoder.com" />
	<CreationDate>2015-04-04 18:51:45Z</CreationDate>
</File>
*/
#endregion

using System;
using System.Reflection;
#if WINDOWS_PHONE
using System.Windows;
#endif

namespace Outcoder.Reflection
{
	public static class AssemblyExensions
	{
		/// <summary>
		/// Retrieves the <c>AssemblyBuildTime</c> for the specified assembly.
		/// <see cref="AssemblyBuildTime"/>
		/// </summary>
		public static AssemblyBuildTime GetBuildTime(this Assembly assembly)
		{
#if !WINDOWS_UWP && !NETFX_CORE
			if (assembly == null)
			{
				assembly = Assembly.GetCallingAssembly();
			}
#else
			ArgumentValidator.AssertNotNull(assembly, "assembly");
#endif
			return new AssemblyBuildTime(assembly.GetName().Version);
		}

#if !WINDOWS_UWP && !NETFX_CORE
		/// <summary>
		/// Retrieves the <c>AssemblyBuildTime</c> for the specified assembly version.
		/// <see cref="AssemblyBuildTime"/>
		/// </summary>
		public static AssemblyBuildTime GetBuildTime(this Version assemblyVersion)
		{
			if (assemblyVersion == null)
			{
				var assembly = Assembly.GetCallingAssembly();
				assemblyVersion = assembly.GetName().Version;
			}

			return new AssemblyBuildTime(assemblyVersion);
		}
#endif
	}

	/// <summary>
	/// This class allows you to retrieve a version number based on the build time of a specified assembly.
	/// </summary>
	public class AssemblyBuildTime
	{
		readonly Version version;
		readonly DateTime timeOfBuild;
		readonly long versionIdentifier;
		readonly string displayVersion;

		/// <summary>
		/// Initializes a new <c>AssemblyBuildTime</c> object using the specified version.
		/// If the provided assembly version is null, the version of the application's entry assembly is used.
		/// </summary>
		/// <param name="assemblyVersion">Can be null, if so the calling assembly version is used.</param>
#if WINDOWS_UWP || NETFX_CORE
		public AssemblyBuildTime(Version assemblyVersion)
		{
			ArgumentValidator.AssertNotNull(assemblyVersion, "assemblyVersion");
#else
		public AssemblyBuildTime(Version assemblyVersion = null)
		{
			if (assemblyVersion == null)
			{
				var assembly = Assembly.GetCallingAssembly();
				assemblyVersion = assembly.GetName().Version;
			}
#endif

			version = assemblyVersion;
			var startDate = new DateTime(2000, 01, 01);
			timeOfBuild = startDate.AddDays(version.Build).AddSeconds(version.Revision * 2);

			var difference = (timeOfBuild - startDate);

			versionIdentifier = (long)difference.TotalSeconds;

			var buildDateTime = new DateTime(2000, 1, 1).Add(new TimeSpan(
				TimeSpan.TicksPerDay * version.Build + // days since 1 January 2000
				TimeSpan.TicksPerSecond * 2 * version.Revision)); // seconds since midnight, (multiply by 2 to get original)

			var month = buildDateTime.Month;
			var day = buildDateTime.Day;
			var hour = buildDateTime.Hour;
			var minute = buildDateTime.Minute;

			displayVersion = string.Format("{0}.{1}.{2:D2}{3:D2}{4:D2}{5:D2}", 
				version.Major, version.Minor, month, day, hour, minute); //version.Build + "." + version.Revision;
		}

		//		static Assembly GetEntryAssembly()
		//		{
		//#if WINDOWS_PHONE
		//			var result = Application.Current.GetType().Assembly;
		//#else
		//			var result = Assembly.GetEntryAssembly();
		//#endif
		//			return result;
		//		}

#if !WINDOWS_UWP && !NETFX_CORE

		static AssemblyBuildTime entryBuildTime;

		/// <summary>
		/// Retrieves the <c>AssemblyBuildTime</c> of the application's entry assembly.
		/// </summary>
		public static AssemblyBuildTime EntryAssemblyBuildTime
		{
			get
			{
				if (entryBuildTime == null)
				{
					entryBuildTime = new AssemblyBuildTime();
				}

				return entryBuildTime;
			}
		}
#endif

		internal Version AssemblyVersion
		{
			get
			{
				return version;
			}
		}

		public string AssemblyFileVersion
		{
			get
			{
				return version.ToString();
			}
		}

		public string DisplayVersion
		{
			get
			{
				return displayVersion;
			}
		}

		public DateTime TimeOfBuild
		{
			get
			{
				return timeOfBuild;
			}
		}

		public long VersionIdentifier
		{
			get
			{

				return versionIdentifier;
			}
		}
	}

}
